/*
 * Project: jcerticles
 * Copyright(c) 2011 jcerticles
 * All rights reserved.
 *
 * $Revision $, last modified $Date $ by $Author $
 */
package com.quintilis31.home.core.content.service.impl;

import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import com.quintilis31.home.common.repository.content.Answer;
import com.quintilis31.home.common.repository.content.Content;
import com.quintilis31.home.common.repository.content.ContentSearchResultsVO;
import com.quintilis31.home.common.repository.content.Question;
import com.quintilis31.home.common.search.impl.searcher.SearchContent;
import com.quintilis31.home.core.content.util.ExamObject;
import com.quintilis31.home.core.content.util.ExamResult;
import com.quintilis31.home.persistence.type.impl.sql.jpa.jpaimpl.PersistenceFactory;

/**
 * All Content related business logic implementations are concentrated here.
 * The following are some of the Content types:
 * Exam Content
 * Searchable Article Content
 * Blog Content
 * @author Jothi
 * @since  1.6
 */
public final class ContentServiceImpl implements com.quintilis31.home.core.content.service.IContentService {

	/**
	 * {@inheritDoc}
	 */
	public List < ContentSearchResultsVO > getFileSearchResultList(String searchQuery, final int skipRecords, final int takeRecords) {		 
		return SearchContent.searchContent(searchQuery, skipRecords, takeRecords);
	}

	/**
	 * {@inheritDoc}
	 */
	public Content getRandomQuestion(final long technologyId) {
		return null; //PersistenceFactory.getContentDAO().getRandomQuestion(technologyId);
	}

	/**
	 * {@inheritDoc}
	 */
	public Question getNextQuestion(final long technologyId, final long testId) {
		return null;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public List < Question > getAllQuestionsForExam(final long technologyId, final	long subTechnologyId) {
		return PersistenceFactory.getContentDAO(Question.class).getAllQuestionsForExam(technologyId, subTechnologyId);
	}	
	
	/**
	 * Fetch all the answers for the given questionId
	 * @param questionId
	 * @return
	 */
	public List < Answer > getAllAnswersForQuestionId(final long questionId) {
		return PersistenceFactory.getContentDAO(Answer.class).getAllAnswersForQuestionId(questionId);		
	}

	/**
	 * {@inheritDoc}
	 */
	public ExamObject createExamObject(final long technologyId, final long subTechnologyId) {
		/* Fetch all the questions and initialize an ExamObject */
		ExamObject examObject = ExamObject.getInstance();
		
		/* Get all the Questions for the given exam */
		/* Get all the Questions for the given exam and fetch the answer for the first Question */
		List < Question > allQuestions = this.getAllQuestionsForExam(technologyId, subTechnologyId);
		List < Answer > asnwersForQuestionId = this.getAllAnswersForQuestionId(allQuestions.get(0).getQuestionId());		
		
		/* Prepare the allQuestionIds for GUI navigation */
		SortedMap < Long, Long > allQuestionIds = new TreeMap < Long, Long > ();

		/* Instantiate the QuestionBank in the ExamObject */
		SortedMap < Question, List < Answer > > questionBank = new TreeMap < Question, List < Answer > > ();
		
		/* Set all the questions as unanswered */
		SortedMap < Long, Long > unansweredQuestionMap = new TreeMap < Long, Long > ();
		
		long count = 0L;
		for (Question question : allQuestions) {
			count = count + 1;
			allQuestionIds.put(count, question.getQuestionId());
			question.setMappedQuestionId(count);
			unansweredQuestionMap.put(count, question.getQuestionId());
			if (count == 1) {
				questionBank.put(question, asnwersForQuestionId);				
			}
			else {
				questionBank.put(question, null);				
			}			
		}		
		examObject.setAllQuestionIds(allQuestionIds);
		examObject.setQuestionBank(questionBank);
		examObject.setUnansweredQuestionIdMap(unansweredQuestionMap);
		
		/* Set the first Question and its Answer as the currentQuestion and currentAnswer */
		examObject.setCurrentAnswers(asnwersForQuestionId);
		examObject.setCurrentQuestion(allQuestions.get(0));
		
		/* Since this is the first call, set the flag currentQuestionAnswered and isEndOfExam to false */
		examObject.setCurrentQuestionAnswered(false);
		examObject.setEndOfExam(false);
		
		return examObject;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public Question getQuestionByQuestionId(final long questionId) {
		
		return null;
	}	
	
	/**
	 * {@inheritDoc}
	 */
	public ExamObject updateExamObjectwithNextQuestion(final ExamObject exam, final List < Long > answers, final long mappedQuestionId) {

		/* Get the actual questionId */
		final long actualQuestionId = exam.getAllQuestionIds().get(mappedQuestionId);
		exam.setMappedQuestionId(mappedQuestionId);
		
		/* Update the question with the answers */
		exam.getAnsweredQuestionsWithAnswers().put(actualQuestionId, answers);
		
		/** 
		 * If the currentQuestionId exists in the unansweredQuestionMap, remove it.
		 * Do this only if the user has answered. 
		 */
		if (answers != null && answers.size() > 0) {
			if (exam.getUnansweredQuestionIdMap().containsKey(actualQuestionId)) {
				exam.getUnansweredQuestionIdMap().remove(actualQuestionId);										
			}
			/* Set the selected by the user in the Answer objects isAnswerSelectedByUser */
			for (Map.Entry < Question, List < Answer > > entry : exam.getQuestionBank().entrySet()) {
				Question ques = entry.getKey();
				if (ques.getQuestionId() == actualQuestionId) {
					List < Answer > ans = entry.getValue();
					for (Answer answer : ans) {
						if (answers.contains(answer.getAnswerId())) {
							answer.setIsAnswerSelectedByUser(true);							
						}
					}
				}
			}
		}

		/* Fetch the next question and answer and set the ExamObject accordingly */
		if (exam.getUnansweredQuestionIdMap().size() > 0) {
			final Long nextQuestionId = exam.getUnansweredQuestionIdMap().get(mappedQuestionId+1);
			for (Map.Entry < Question, List < Answer > > entry : exam.getQuestionBank().entrySet()) {
			    Question ques = entry.getKey();
			    if (ques.getQuestionId() == nextQuestionId) {
			    	List < Answer > ans = entry.getValue();
			    	/* If not, fetch it from the database */
			    	if (ans == null) {
			    		ans = this.getAllAnswersForQuestionId(nextQuestionId);
			    		exam.getQuestionBank().put(ques, ans);
			    	}
		    		/* update the ExamObject for the current question and answer */			    		
					exam.setCurrentQuestion(ques);
					exam.setCurrentAnswers(ans);				    	
			    }					
			}
		}
		else {
			/* Indicate end of exam */
			exam.setEndOfExam(true);
		}

		return exam;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public ExamObject updateExamObjectForQuestionId(final ExamObject exam, final long mappedQuestionId) {

		/* Get the actual questionId */
		final long actualQuestionId = exam.getAllQuestionIds().get(mappedQuestionId);
		exam.setMappedQuestionId(mappedQuestionId);
		
		/* Check in the ExamObject if this selectedQuestionId is already answered */
		if (exam.getAnsweredQuestionsWithAnswers().containsKey(actualQuestionId)) {
			/* Set the flag in ExamObject for UI manipulation */
			exam.setCurrentQuestionAnswered(true);						
		}
		else {
			/* Set the flag in ExamObject for UI manipulation */
			exam.setCurrentQuestionAnswered(false);
		}
		
		/* Check if we have already fetched the Answer for this questionId */
		for (Map.Entry < Question, List < Answer > > entry : exam.getQuestionBank().entrySet()) {
		    Question ques = entry.getKey();
		    if (ques.getQuestionId() == actualQuestionId) {
		    	List < Answer > ans = entry.getValue();
		    	/* If not, fetch it from the database */
		    	if (ans == null) {
		    		ans = this.getAllAnswersForQuestionId(actualQuestionId);
		    		exam.getQuestionBank().put(ques, ans);
		    	}
		    	/* update the ExamObject for the current question and answer */
				exam.setCurrentQuestion(ques);
				exam.setCurrentAnswers(ans);
		    }
		}
		
		return exam;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public ExamObject finishAndEvaluateExam(final ExamObject exam) {
		// TODO...Transfer the following data to the QuestionBank for showing a detailed report to the user
		// isAnswered, Answers entered by user for the question,
		
		// Logic for showing exam review...
		Map < Long, List < Long > > unansweredQuestionsList = exam.getAnsweredQuestionsWithAnswers();
		
		for (Map.Entry < Question, List < Answer > > entry : exam.getQuestionBank().entrySet()) {
		    Question ques = entry.getKey();
		    
		    if(!unansweredQuestionsList.containsKey(ques.getMappedQuestionId())) {
		    	ques.setIsAnswered(true);
		    	ques.setAnswersGivenByUser(exam.getAnsweredQuestionsWithAnswers().get(ques.getMappedQuestionId()));
		    }
		}
		
		// TODO... Evaluation for exam
		ExamResult examResult = new ExamResult();
		examResult.setPass(true);
		
		return exam;		
	}
}